<?php


namespace app\controller\api;


use app\common\model\RecordCommon;
use app\common\service\qrcode\GenerateCode;
use app\common\service\redis\PoolRedis;
use app\model\AdminStaff as StaffModel;
use app\model\AdminStaff;
use app\model\AdminStaffIcCard;
use app\model\AdminStudentDormitory;
use app\util\ReturnCode;
use app\util\Strs;
use app\util\Tools;
use think\facade\Cache;
use think\facade\Log;
use think\facade\Request;
use think\facade\Validate;
use think\Response;

class DoorLock extends Base
{
    public function tempPassword() : Response {
        return $this->buildFailed(ReturnCode::AUTH_ERROR, '该功能暂未开放');
        $validate = Validate::rule([
            'uuid|用户'  => 'require',
            'dormitory_id|宿舍楼' => 'require',
            'student_dormitory_id|宿舍' => 'require',
            'flag|获取方式' => 'require|in:1,2'
        ]);
        if (!$validate->check(input('get.'))) {
            return $this->buildFailed(ReturnCode::PARAM_INVALID, $validate->getError());
        }
        $dormitory_id = input('get.dormitory_id/d');
        $student_dormitory_id = input('get.student_dormitory_id/d');
        $staff = AdminStaff::where([
            'is_delete' => 0,
            'status' => AdminStaff::AUDIT_PASS,
            'uuid' => input('get.uuid/s'),
        ])->find();
        if (!$staff) {
            return $this->buildFailed(ReturnCode::RECORD_NOT_FOUND, '账号不存在或未审核通过');
        }
        if ($staff->type == 0 && $staff->expire_flag) {
            return $this->buildFailed(ReturnCode::AUTH_ERROR, '账号已过期，无法登录');
        }
        $card = AdminStaffIcCard::where([
            'staff_id' => $staff->id,
            'school_id' => $staff->school_id,
            'dormitory_id' => $dormitory_id,
            'student_dormitory_id' => $student_dormitory_id,
            'is_delete' => 0
        ])->find();
        if (!$card) {
            return $this->buildFailed(ReturnCode::AUTH_ERROR, '账号没有该宿舍门锁权限');
        }
        $flag = input('get.flag/d');
        if ($flag == 1) {// 离线密码
            //$no = AdminStudentDormitory::dynamicDistribution($staff->toArray(),$student_dormitory_id);
            $number = '';
            for ($i=1;$i<7;$i++) {
                $number .= $no;
            }
            $number = intval(substr($number, 0, 6));
            $date[0] = date("j");
            $date[1] = date("H");
            $date[2] = date("i")+0;
            $data['password'] = (($number%10000)^($date[1]*100+$date[2])^($date[2]%10*1111)^(floor($number/10000)*100+$date[0]))+($date[2]%10*100000);
            // 不足6位,左边补零
            $data['password'] = str_pad($data['password'],6,0,STR_PAD_LEFT);
        } else { // 在线密码
            if (!in_array(AdminStaffIcCard::TEMP_PWD, $card->lock_permission_arr)) {
                return $this->buildFailed(ReturnCode::AUTH_ERROR, '没有该宿舍临时密码开锁权限');
            }
            $data['password'] = (int)Strs::randString(8, 1);
            $data['start'] = time();
            $data['end'] = strtotime("+1 day");
            $redis = PoolRedis::instance();
            $key = 'temp_pw:'.$staff->uuid.":".$student_dormitory_id;
            $redis->delete($key);
            $redis->hSet($key, 'pwd', $data['password']);
            $redis->hSet($key, 'start', $data['start']);
            $redis->hSet($key, 'end', $data['end']);
            $redis->expire($key, 60*60*24); // 24小时
        }
        RecordCommon::saveUnLockPassword($staff->school_id, $dormitory_id, $student_dormitory_id, $staff->id, $flag, $data['password']);
        return $this->buildSuccess($data);
    }

    /**
     * @func record
     * @method POST
     * @desc 蓝牙开锁、超级SIM卡/IC卡开锁等记录同步
     * @param integer $type 开锁方式：0--蓝牙 1--SIM卡 2--在线密码  3--ic卡 4--离线密码
     * @return Response
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @Time: 2022/1/11 18:04
     */
    public function record() : Response {
        $postData = input('post.');
        $postData['status'] = $postData['status'] ?? 1;
        $validate = Validate::rule([
            'type|开锁方式' => 'require|in:0,1,2,3,4',
            'open_time|开锁时间' => 'require|number|max:11',
            'uuid|用户'  => 'require',
            'user_number|用户编号' => 'require|number',
            'dormitory_id|宿舍号' => 'require|number',
            'student_dormitory_id|宿舍号' => 'require|number',
            'status|开锁状态' => 'require|in:0,1'
        ]);
        if (!$validate->check($postData)) {
            return $this->buildFailed(ReturnCode::PARAM_INVALID, $validate->getError());
        }
        $staff = AdminStaff::where([
            'is_delete' => 0,
            'status' => AdminStaff::AUDIT_PASS,
            'uuid' => $postData['uuid'],
        ])->find();
        if (!$staff) {
            return $this->buildFailed(ReturnCode::RECORD_NOT_FOUND, '账号不存在或未审核通过');
        }
        // 通过用户编号获取真实开锁用户
        if ($postData['user_number'] > -1) {
            $redis = PoolRedis::instance();
            $number = $redis->hGetAll(AdminStudentDormitory::NO_KEY."{$staff->school_id}:{$postData['student_dormitory_id']}:no");
            $number = array_flip($number);
            $staff_id = isset($number[$postData['user_number']]) ? $number[$postData['user_number']] : null;
            if ($staff_id) {
                $staff = AdminStaff::find($staff_id);
                $typeText = $staff->type_text;
            } else {
                return $this->buildSuccess();
            }
            // 蓝牙开锁的已当前时间为开锁时间
            if ($postData['type'] == 0) {
                $postData['open_time'] = time();
            }
            RecordCommon::saveUnLockRecord($staff->school_id, $postData['dormitory_id'], $postData['student_dormitory_id'], $staff_id, $typeText, $postData['type'], $postData['status'], $postData['open_time']);
        }
        return $this->buildSuccess();
    }

    /**
     * @func recordList
     * @param uuid 用户标识 begin-end 出入时间范围
     * @method GET
     * @desc 出入记录
     * @return Response
     * @Time: 2022/3/15 15:00
     */
    public function recordList(): Response
    {
        $data     = Request::param(['uuid', 'begin', 'end', 'page']);
        $limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
        $start = $this->request->get('page', 1);
        $validate = Validate::rule([
            'uuid|用户标识' => 'require',
        ]);
        if (!$validate->check($data)) {
            return $this->buildFailed(ReturnCode::PARAM_INVALID, $validate->getError());
        }
        $staff_id = AdminStaff::where('uuid', $data['uuid'])->where('is_delete', 0)->value('id');
        if (!$staff_id) {
            return $this->buildFailed(ReturnCode::RECORD_NOT_FOUND, '账号不存在');
        }
        $where = [
            ['staff_id', '=', $staff_id]
        ];
        if (isset($data['begin']) && isset($data['end'])) {
            array_push($where, ['create_time', '>=', strtotime($data['begin'])]);
            array_push($where, ['create_time', '<=', strtotime($data['end']." 23:59:59")]);
        }
        return $this->buildSuccess(RecordCommon::getUnlockRecord($where, $start, $limit));
    }

    /**
     * @func recordRkeList
     * @param uuid 用户标识 begin-end 出入时间范围
     * @method GET
     * @desc 出入记录
     * @return Response
     * @Time: 2022/3/15 15:00
     */
    public function recordRkeList(): Response
    {
        $data     = Request::param(['uuid', 'begin', 'end', 'page']);
        $limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
        $start = $this->request->get('page', 1);
        $validate = Validate::rule([
            'uuid|用户标识' => 'require',
        ]);
        if (!$validate->check($data)) {
            return $this->buildFailed(ReturnCode::PARAM_INVALID, $validate->getError());
        }
        $staff_id = AdminStaff::where('uuid', $data['uuid'])->where('is_delete', 0)->value('id');
        if (!$staff_id) {
            return $this->buildFailed(ReturnCode::RECORD_NOT_FOUND, '账号不存在');
        }
        $where = [
            ['staff_id', '=', $staff_id]
        ];
        if (isset($data['begin']) && isset($data['end'])) {
            array_push($where, ['create_time', '>=', strtotime($data['begin'])]);
            array_push($where, ['create_time', '<=', strtotime($data['end']." 23:59:59")]);
        }
        return $this->buildSuccess(RecordCommon::getRkeRecord($where, $start, $limit));
    }

    // 删除锁用户列表
    public function clearList() : Response {
        $data = Request::param(['school_id', 'student_dormitory_id']);
        $validate = Validate::rule([
            'school_id|学校' => 'require|number',
            'student_dormitory_id|宿舍号' => 'require|number',
        ]);
        if (!$validate->check($data)) {
            return $this->buildFailed(ReturnCode::PARAM_INVALID, $validate->getError());
        }
        $redis = PoolRedis::instance();
        $distributionKey = AdminStudentDormitory::NO_KEY."{$data['school_id']}:{$data['student_dormitory_id']}:del";
        if (Request::isPut()) {
            // 确认删除锁内用户信息
            $redis->delete($distributionKey);
            return $this->buildSuccess([], '删除成功');
        }
        $list = $redis->hGetAll($distributionKey);
        $arr = [];
        if ($list) {
            foreach ($list as $key => $item) {
                $temp['no'] = $key;
                $staffIcCard = AdminStaffIcCard::where([
                    'staff_id' => $item,
                    'student_dormitory_id' => $data['student_dormitory_id'],
                    'is_delete' => 1
                ])->order('update_time', 'desc')->find();
                if ($staffIcCard){
                    $temp['whitelist_no'] = $staffIcCard['whitelist_no'];
                    $temp['ic_card'] = $staffIcCard['ic_card'];
                    $temp['sim_uid'] = $staffIcCard['sim_uid'];
                }
                array_push($arr, $temp);
            }
        }

        return $this->buildSuccess($arr);
    }

    // 删除锁卡片列表
    public function clearCardList() : Response {
        $data = Request::param(['school_id', 'student_dormitory_id']);
        $validate = Validate::rule([
            'school_id|学校' => 'require|number',
            'student_dormitory_id|宿舍号' => 'require|number',
        ]);
        if (!$validate->check($data)) {
            return $this->buildFailed(ReturnCode::PARAM_INVALID, $validate->getError());
        }
        $redis = PoolRedis::instance();
        $distributionKey = AdminStudentDormitory::NO_KEY."{$data['school_id']}:{$data['student_dormitory_id']}:del_card";
        if (Request::isPut()) {
            // 确认删除锁内用户信息
            $redis->delete($distributionKey);
            return $this->buildSuccess([], '删除成功');
        }
        $list = $redis->hGetAll($distributionKey);
        $arr = [];
        if ($list) {
            foreach ($list as $key => $item) {
                $temp['card_id'] = $key;
                array_push($arr, $temp);
            }
        }
        return $this->buildSuccess($arr);
    }

    // 管理员用户列表
    public function staffList() : Response {
        $data = Request::param(['school_id', 'student_dormitory_id']);
        $validate = Validate::rule([
            'school_id|学校' => 'require|number',
            'student_dormitory_id|宿舍号' => 'require|number',
        ]);
        if (!$validate->check($data)) {
            return $this->buildFailed(ReturnCode::PARAM_INVALID, $validate->getError());
        }
        $stu_sub_query = AdminStudentDormitory
            //::cache(true,60)
            ::where('is_delete', 0)
            ->field('id,name student_dormitory_name,uuid,door_type');
        // 找出当前宿舍管理员
        $stu_sub_query = $stu_sub_query->buildSql();
        $result = AdminStaffIcCard::alias('card')
            ->join([$stu_sub_query => 'sd'], 'sd.id=card.student_dormitory_id')
            ->join(['admin_staff' => 'staff'], 'staff.id=card.staff_id')
            ->where('staff.type', '<>', 0)
            ->where([
                'card.is_delete' => 0,
                'card.student_dormitory_id' => $data['student_dormitory_id'],
                'card.school_id' => $data['school_id']
            ])
            ->with(['staff'])
            ->order('card.activate_time','asc')
            ->hidden(['school_id','create_time','update_time','is_delete'])
            ->select()->toArray();
        $resultTmp = [];
        foreach ($result as $key => $item) {
            $staff = $item['staff'];
            //$result[$key]['sim_uid'] = $staff['sim_card'];
            // 没有IC卡和SIM卡不分配编号
            if ((empty($result[$key]['ic_card']) || $result[$key]['ic_card']=='00000000')
                && (empty($result[$key]['sim_uid']) || $result[$key]['sim_uid']=='00000000000000000000')) {
                unset($result[$key]);
            } else {
                $result[$key]['no'] = (int)AdminStudentDormitory::dynamicDistribution($staff,$data['student_dormitory_id'],$item['door_type']);
                Log::error('staffList :'.$staff['id'].' | 姓名:'.$staff['name'].' | 宿舍号:'.$item['student_dormitory_name'].' | '.$item['door_type'].' | 分配编号:'.$result[$key]['no'].' | IC:'.$result[$key]['ic_card'].' | SIM:'.$result[$key]['sim_uid']);
                $result[$key]['offline_pwd_factor'] = '';
                $result[$key]['online_pwd'] = [];
                if ($item['lock_permission']) {
                    $result[$key]['lock_permission_arr'] = array_map(function ($i) {
                        return (int)$i;
                    }, explode(',', $item['lock_permission']));
                }
                unset($result[$key]['lock_permission']);
                unset($result[$key]['staff']);
                $resultTmp[] = $result[$key];
            }
        }
        return $this->buildSuccess($resultTmp);
    }

    // 电量上传
    public function uploadVoltage() : Response {
        $data = Request::param(['school_id', 'student_dormitory_id', 'voltage', 'version']);
        $validate = Validate::rule([
            'student_dormitory_id|宿舍号' => 'require|number',
            'voltage|电量电压' => 'require|float',
        ]);
        if (!$validate->check($data)) {
            return $this->buildFailed(ReturnCode::PARAM_INVALID, $validate->getError());
        }
        $studentDormitory = AdminStudentDormitory::where([
            'is_delete' => 0,
            'id' => $data['student_dormitory_id']
        ])->find();
        if (!$studentDormitory){
            return $this->buildFailed(ReturnCode::RECORD_NOT_FOUND, '找不到宿舍');
        }
        if($studentDormitory->voltage != $data['voltage'] || $studentDormitory->remark != $data['version']) {
            $studentDormitory->voltage = $data['voltage'];
            $studentDormitory->remark = $data['version'];
            $studentDormitory->voltage_time = time();
            $studentDormitory->save();
        }
        return $this->buildSuccess([], '更新成功');
    }

    /**
     * @func code
     * @method GET
     * @desc 闸机过站二维码刷新
     * @return Response
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @Time: 2021/12/9 12:18
     */
    public function code() : Response {
        $validate = Validate::rule([
            'uuid'  => 'require',
        ]);
        if (!$validate->check(input('get.'))) {
            return $this->buildFailed(ReturnCode::PARAM_INVALID, $validate->getError());
        }
        $staff = StaffModel::where('uuid', input('get.uuid'))->where('is_delete', 0)->find();
        if (!$staff) {
            return $this->buildFailed(ReturnCode::NOT_EXISTS, '账号不存在');
        }
        if ($staff->status != StaffModel::AUDIT_PASS) {
            return $this->buildFailed(ReturnCode::AUTH_ERROR, '账号未审核通过');
        }
        if ($staff->type == 0 && $staff->expire_flag) {
            return $this->buildFailed(ReturnCode::AUTH_ERROR, '账号已过期，无法登录');
        }
        $str = "id={$staff->id}&time=".time();
        $token = Tools::userMd5($str);

        $redis = PoolRedis::instance();
        if (!$redis->setnx("D_LOCKS:".$token, $staff->id)) {
            return $this->buildFailed(ReturnCode::INVALID, '请勿频繁刷新');
        }
        $redis->expire("D_LOCKS:".$token, config('apiadmin.LOCK_TOKEN_TIME_OUT'));

        return $this->buildSuccess(['token' => $token]);
    }
}